using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Mail;
using System.Security.Cryptography;
using System.Security.Principal;
using System.Text;
using System.Web;
using System.Web.Security;
using C3.Directory.Services;
using CSI.Directory.Core.Model;
using CSI.Directory.Core.Repositories;
using CSI.Directory.Core.Services;
using log4net;
using RNGCryptoServiceProvider=System.Security.Cryptography.RNGCryptoServiceProvider;
using SHA256Managed=System.Security.Cryptography.SHA256Managed;

namespace CSI.Directory.Services
{
    public class UserService : ServiceBase, IUserService
    {
        
        public UserService(ISessionService sessionService, IUserRepository userRepo, IDirectoryRepository directoryRepository)
            : base(sessionService, userRepo, directoryRepository)
        {
            HashProvider = new SHA256Managed();
            SalthLength = 8;
            
        }
        private static readonly ILog Log = LogManager.GetLogger(typeof(UserService));
        private SaltedHashProvider saltedHashProvider;
        public SaltedHashProvider SaltedHashProvider
        {
            get
            {
                return saltedHashProvider ?? new SaltedHashProvider();
            }

            set {saltedHashProvider = value; }
        }
        HashAlgorithm HashProvider;
        int SalthLength;

        public TransactionResult LoginUser(string email, string password, bool remember)
        {

            var t = new TransactionResult() { Successful = false };
            try
            {
                if (!IsAuthenticated(email, password))
                    return t;

                //get user with hashed password
                var user = SessionService.CurrentUser;
                //var roles = GetRoles();
                FormsAuthenticationTicket authTicket;
                if (remember)
                {
                    authTicket = new FormsAuthenticationTicket(1, user.Name,
                                                               DateTime.Now, DateTime.Now.AddMonths(3), true, user.Roles);
                }
                else
                {
                    authTicket = new FormsAuthenticationTicket(1, user.Name,
                                                               DateTime.Now, DateTime.Now.AddMinutes(120), false,
                                                               user.Roles);
                }
                // Now encrypt the ticket.
                var encryptedTicket = FormsAuthentication.Encrypt(authTicket);
                // Create a cookie and add the encrypted ticket to the 
                // cookie as data.
                var authCookie =
                    new HttpCookie(FormsAuthentication.FormsCookieName,
                                   encryptedTicket);
                HttpContext.Current.Response.Cookies.Add(authCookie);
                //if (remember)
                //{
                //    var c = new HttpCookie(ConfigurationManager.AppSettings["UserCookie"])
                //                {
                //                    Expires = DateTime.Now.AddMonths(3),
                //                    Value = user.Name + "-" + user.Password
                //                };
                //    HttpContext.Current.Response.Cookies.Add(c);
                //}
                // Add the cookie to the outgoing cookies collection.
                //var identity = new GenericIdentity(user.Name);
                //var principal = new GenericPrincipal(identity, (string.IsNullOrEmpty(user.Roles) ? null : user.Roles.Split(',')));
                //HttpContext.Current.User = principal;
                t.Successful = true;
                var listing = DirectoryRepository.GetListingsByUserId(user.Id);
                user.IsListed = (listing.Count > 0) ? true : false;
                return t;
            }
            catch (Exception ex)
            {

                Log.Error(ex);
                t.Exception = ex.Message;
                return t;

            }

        }
        
        public string SaltAndHashPassword(User u)
        {
            string hash,salt;
            SaltedHashProvider.GetHashAndSaltString(u.Password,out hash,out salt);
            u.Salt = salt;
            return hash;
        }
        public bool IsAuthenticated(string email, string password)
        {
            /*   1. The users enters the password
                 2. The system looks up the stored hash + salt
                 3. The system tries if a new hash of the given password + salt matches the stored hash
                 4. If they match the user can login 
             */
            var u = UserRepository.GetUserByEmail(email);
            if (u==null)
                return false;
            var auth = SaltedHashProvider.VerifyHashString(password, u.Password, u.Salt);
            if (auth)
            {
                SessionService.CurrentUser = u;
            }
            return auth;
        }

       

        public void LogoutUser()
        {
            FormsAuthentication.SignOut();
            HttpContext.Current.Response.Cookies[FormsAuthentication.FormsCookieName].Expires = DateTime.Now;
            HttpContext.Current.Session.Abandon();
        }

        public User GetUserById(int id)
        {
           
            
            try
            {

                return ((IRepositoryBase) UserRepository).GetById<User>(id);

            }
            catch (Exception ex)
            {

                if (ex.InnerException != null) Log.Error(ex.Message + Environment.NewLine + ex.InnerException);
                else Log.Error(ex.Message);

                return null;
            }
        
        }

        public User GetUserByEmail(string email)
        {
            try
            {

                return UserRepository.GetUserByEmail(email);


            }
            catch (Exception ex)
            {

                Log.Error(ex);

                return null;
            }
        }

        public TransactionResult RegisterUser(string firstname, string lastname, string password, string email)
        {
            var t = new TransactionResult() {Successful = false};
            try
            {
                var user = new User()
                            {
                                Name = firstname + " " + lastname,
                                CreateDate = DateTime.Now,
                                ModifiedDate = DateTime.Now,
                                Password = password,
                                Email = email,
                                Roles = "user",
                                FirstName = firstname,
                                LastName = lastname,
                                SetUpComplete = false
                            };
                user.Password = SaltAndHashPassword(user);
                ((IRepositoryBase)UserRepository).Add(user);
                t.ReturnVal = user.Id;
                if (Int32.Parse(t.ReturnVal.ToString()) > 0)
                    t.Successful = true;
                LoginUser(email, password, false);
                return t;
                

            }
            catch (Exception ex)
            {

                Log.Error(ex);

                return t;
            }
        }

        public TransactionResult UpdateUser(int id, string address, string city, string state, 
            string zipcode, string phone, string package1, string package2)
        {
            var t = new TransactionResult() { Successful = false };
            try
            {
                var user = ((IRepositoryBase) UserRepository).GetById<User>(id);
                user.Address = address;
                user.City = city;
                user.State = state;
                user.Zip = zipcode;
                user.Phone = phone;
                user.Package = Convert.ToInt32(package1);
                user.Option = Convert.ToInt32(package2);
                user.SetUpComplete = true;
                user.IsListed = false;
                ((IRepositoryBase) UserRepository).Update(user);
                //update session user so that the new values will be set
                SessionService.CurrentUser = user;
                return t;


            }
            catch (Exception ex)
            {

                Log.Error(ex);

                return t;
            }
        }

        public TransactionResult AddUserToCRM(int id)
        {
            var t = new TransactionResult() { Successful = false };
            try
            {
                return t;
            }
            catch (Exception ex)
            {

                Log.Error(ex);

                return t;
            }
        }

        public TransactionResult RegisterUser(string firstname, string lastname, string password, string email, string role)
        {
            var t = new TransactionResult() { Successful = false };
            try
            {
                var user = new User()
                {
                    Name = firstname + " " + lastname,
                    CreateDate = DateTime.Now,
                    ModifiedDate = DateTime.Now,
                    Password = password,
                    Email = email,
                    Roles = role,
                    FirstName = firstname,
                    LastName = lastname,
                    SetUpComplete = true
                };
                user.Password = SaltAndHashPassword(user);
                ((IRepositoryBase)UserRepository).Add(user);
                t.ReturnVal = user.Id;
                t.Successful = true;
                return t;


            }
            catch (Exception ex)
            {

                Log.Error(ex);
                t.Exception = ex.Message;
                return t;
            }
        }

        public IList<User> GetAllUsers()
        {
            try
            {
                return ((IRepositoryBase)UserRepository).GetAll<User>();
            }
            catch (Exception ex)
            {

                Log.Error(ex.Message);
                return new List<User>();
            }
        }

        public TransactionResult ChangePassword(int id, string password)
        {
            var t = new TransactionResult() { Successful = false };
            try
            {
                var user = ((IRepositoryBase)UserRepository).GetById<User>(id);
                user.Password = password;
                user.Password = SaltAndHashPassword(user);
                ((IRepositoryBase)UserRepository).Update(user);
                t.Successful = true;
                return t;


            }
            catch (Exception ex)
            {

                Log.Error(ex);
                t.Exception = ex.Message;
                return t;
            }
        }

        public TransactionResult RenewUser(int id, string renewal)
        {
            var t = new TransactionResult() { Successful = false };
            try
            {
                var user = ((IRepositoryBase)UserRepository).GetById<User>(id);
                user.CreateDate = DateTime.Parse(renewal);
                ((IRepositoryBase)UserRepository).Update(user);
                t.Successful = true;
                return t;


            }
            catch (Exception ex)
            {

                Log.Error(ex);
                t.Exception = ex.Message;
                return t;
            }
        }

        public TransactionResult ResetPassword(string email)
        {
            var t = new TransactionResult() { Successful = false };
            try
            {
                var user = UserRepository.GetUserByEmail(email);
                var p = user.Password = CreateRandomPassword(5);
                user.Password = SaltAndHashPassword(user);
                ((IRepositoryBase)UserRepository).Update(user);
                var smtp = new SmtpClient("mail.csintel.com", 25);
                smtp.Credentials = new NetworkCredential("Keenan.Green", "KG1@csi");

                var to = new MailAddress(email);

                var from = new MailAddress("keenan.green@csintel.com");
                var m = new MailMessage(from, to)
                {
                    IsBodyHtml = true,
                    Body = string.Format("Your Eagleford Flyer password has been reset to: {0}",p),
                    Subject = "Eagleford Flyer Password Reset"
                };

                smtp.Send(m);
                t.Successful = true;
                return t;


            }
            catch (Exception ex)
            {

                Log.Error(ex);
                t.Exception = ex.Message;
                return t;
            }
        }

        private static string CreateRandomPassword(int passwordLength)
        {
            var allowedChars = "abcdefghijkmnopqrstuvwxyzABCDEFGHJKLMNOPQRSTUVWXYZ0123456789";
            var chars = new char[passwordLength];
            var rd = new Random();

            for (var i = 0; i < passwordLength; i++)
            {
                chars[i] = allowedChars[rd.Next(0, allowedChars.Length)];
            }

            return new string(chars);
        }
    }
}